#include "key_task.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "gpio.h"
#include "stm32f4xx.h"

#define KEY_EVENT_QUEUE_SIZE 20
#define KEY_RESULT_QUEUE_SIZE 10

static QueueHandle_t g_key_event_queue_handle;
static QueueHandle_t g_key_result_queue_handle;
key_event_t key_event;
key_result_t key_result;
key_event_t *pkey_event;
key_result_t *pkey_result;


static void key_init(void);
static void GPIO_Trigger_deal(key_state_t key_state);
static void key_task(void);
static key_result_t* keyGetResult(void);

KeyInterface_t key_interface = {
    .pfinit = key_init,
    .pftask = key_task,
    .pfget_result = keyGetResult
};

static void key_init(void)
{
    g_key_event_queue_handle = xQueueCreate( KEY_EVENT_QUEUE_SIZE, sizeof((void*)pkey_event) );
    g_key_result_queue_handle = xQueueCreate( KEY_RESULT_QUEUE_SIZE, sizeof((void*)pkey_result) );
}

static void key_task(void)
{
    static uint8_t short_press_flag = 0;
    static uint32_t tick_press;
    pkey_result = &key_result;
    if ( pdTRUE == xQueueReceive(g_key_event_queue_handle, &pkey_event, 200) )
    {
        if (key_event.state == KEY_PRESS)
        {
            tick_press = key_event.trigger_tick;
        }
        else if (key_event.state == KEY_RELEASE)
        {
            printf("tick difference: %d\r\n", key_event.trigger_tick - tick_press);
            if ((key_event.trigger_tick - tick_press > 10) && (key_event.trigger_tick - tick_press < 3000))
            {
                tick_press = key_event.trigger_tick;
                if (short_press_flag > 0)
                {
                    short_press_flag = 0;
                    key_result = KEY_DOUBLE_PRESS;
                    xQueueSendToBack(g_key_result_queue_handle, &pkey_result, 100);
                    printf("key result: double press\r\n");
                }
                else 
                {
                    short_press_flag = 1;
                    printf("set short press flag\r\n");
                }
            }
            else if ((key_event.trigger_tick - tick_press) >= 3000)
            {
                tick_press = key_event.trigger_tick;
                key_result = KEY_LONG_PRESS;
                xQueueSendToBack(g_key_result_queue_handle, &pkey_result, 100);
                printf("key result: long press\r\n");
            }
            else
            {

            }
        }
    }
    else if(short_press_flag > 0)
    {
        short_press_flag = 0;
        key_result = KEY_SHORT_PRESS;
        xQueueSendToBack(g_key_result_queue_handle, &pkey_result, 100);
        printf("key result: short press\r\n");
    }
}

static key_result_t* keyGetResult(void)
{
    if (pdTRUE == xQueueReceive(g_key_result_queue_handle, &pkey_result, portMAX_DELAY))
    {
        return pkey_result;
    }
    else
    {
        return 0;
    }
}

static void GPIO_Trigger_deal(key_state_t key_state)
{
    pkey_event = &key_event;
    GPIO_InitTypeDef GPIO_InitStructure={0};
    if (pkey_event->state != key_state)
    {
        pkey_event->state = key_state;
        if (KEY_PRESS == pkey_event->state)
        {
            GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
        }
        else if (KEY_RELEASE == pkey_event->state)
        {
            GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
        }

        pkey_event->key_type = KEY_USER_KEY;
        pkey_event->trigger_tick = HAL_GetTick();

        GPIO_InitStructure.Pin = KEY_Pin;
        GPIO_InitStructure.Pull = GPIO_PULLUP;
        HAL_GPIO_Init(KEY_GPIO_Port, &GPIO_InitStructure);

        xQueueSendFromISR(g_key_event_queue_handle, &pkey_event, NULL);

        printf("key trigger: %d \t key state: %d\r\n", pkey_event->key_type, pkey_event->state);
    }
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == KEY_Pin)
    {
        if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin))
        {
            GPIO_Trigger_deal(KEY_PRESS);
        } 
        else
        {
            GPIO_Trigger_deal(KEY_RELEASE);
        }
    }
}
